<?php

    namespace utils;
    /**
     * @name PHPTree
     * @author  crazymus < QQ:291445576 >
     * @des     PHP生成树形结构,无限多级分类
     * @version 1.2.0
     * @Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
     * @updated 2015-08-26
     */
    class PHPTree
    {

        protected static array $config = [
            /* 主键 */
            'primary_key'  => 'id',
            /* 父键 */
            'parent_key'   => 'pid',
            /* 展开属性 */
            'expanded_key' => 'expanded',
            /* 叶子节点属性 */
            'leaf_key'     => 'leaf',
            /* 孩子节点属性 */
            'children_key' => 'children',
            /* 是否展开子节点 */
            'expanded'     => false
        ];

        /* 结果集 */
        protected static array $result = [];

        /* 层次暂存 */
        protected static array $level = [];

        /**
         * 生成树形结构
         *
         * @param array $data    二维数组
         * @param array $options 多维数组
         *
         * @return array
         */
        public static function makeTree (array $data, array $options = []): array
        {
            $dataset = self::buildData( $data, $options );
            return self::makeTreeCore( 0, $dataset, 'normal' );
        }

        /* 生成线性结构, 便于HTML输出, 参数同上 */
        public static function makeTreeForHtml ($data, $options = []): array
        {

            $dataset = self::buildData( $data, $options );
            $r       = self::makeTreeCore( 0, $dataset, 'linear' );
            return $r;
        }

        /* 格式化数据, 私有方法 */
        private static function buildData ($data, $options): array
        {
            $config       = array_merge( self::$config, $options );
            self::$config = $config;
            extract( $config );

            $r = [];
            foreach ( $data as $item ) {
                $id                 = $item[$primary_key];
                $parent_id          = $item[$parent_key];
                $r[$parent_id][$id] = $item;
            }

            return $r;
        }

        /* 生成树核心, 私有方法  */
        private static function makeTreeCore ($index, $data, $type = 'linear'): array
        {
            extract( self::$config );
            foreach ( $data[$index] as $id => $item ) {
                if ( $type == 'normal' ) {
                    if ( isset( $data[$id] ) ) {
                        $item[$expanded_key] = self::$config['expanded'];
                        $item[$children_key] = self::makeTreeCore( $id, $data, $type );
                    } else {
                        $item[$leaf_key] = true;
                    }
                    $r[] = $item;
                } else if ( $type == 'linear' ) {
                    $parent_id        = $item[$parent_key];
                    self::$level[$id] = $index == 0 ? 0 : self::$level[$parent_id] + 1;
                    $item['level']    = self::$level[$id];
                    self::$result[]   = $item;
                    if ( isset( $data[$id] ) ) {
                        self::makeTreeCore( $id, $data, $type );
                    }

                    $r = self::$result;
                }
            }
            return $r;
        }
    }

